#define _AIRPLANE_
#ifdef _AIRPLANE_
#include "Definitions.h"
#include "ReadFifo.h"
#include "WriteFifo.h"
#include "Logger.h"
#include "Message.h"
#include "Config.h"
#include <stdio.h>
#include <sstream>
#include <stdlib.h>
#include <time.h>

#include "Semaforo.h"
#include "SharedCounter.h"


void take_off(unsigned long airstip){
	//Despegando
	Logger::getInstance().logMessage(Logger::TRACE, "despegando");
	sleep(3);
}

void land(unsigned long airstip){
	//aterrizando
	Logger::getInstance().logMessage(Logger::TRACE, "aterrizando");
	sleep(3);
}

void fly(){
	srand(time(NULL) + getpid());
	Logger::getInstance().logMessage(Logger::TRACE, "en vuelo");
	sleep(rand() % 15);
}

void get_authorization(DECISION dec, std::string name){

	char buffer[sizeof(unsigned int) + sizeof(unsigned long)];
	void (*use_airstrip)(unsigned long) = NULL;

	if(dec == TAKEOFF)
		use_airstrip = take_off;
	else if(dec == LAND)
		use_airstrip = land;

	if(use_airstrip != NULL) {
		Logger::getInstance().logMessage(Logger::TRACE, "Pedi autorizacion para pista");
		ReadFifo fifo(name);
		Logger::getInstance().logMessage(Logger::TRACE, "Abro pipe de lectura");
		fifo.open_();
		Logger::getInstance().logMessage(Logger::TRACE, "Pipe abierto");

		Logger::getInstance().logMessage(Logger::DEBUG, "leyendo mensaje desde fifo: " + name);
		Logger::getInstance().logMessage(Logger::TRACE, "Voy a leer mensaje");
		ssize_t readedBytes = fifo.read_(static_cast<void*> (buffer), sizeof(unsigned int) + sizeof(unsigned long));
		Message msg(buffer, sizeof(unsigned int) + sizeof(unsigned long));
		if (readedBytes < msg.size()){
			Logger::getInstance().logMessage(Logger::ERROR, "Error al recibir mensaje");
		}
		Logger::getInstance().logMessage(Logger::TRACE, "Autorizado");
		Logger::getInstance().logMessage(Logger::TRACE, "Voy a usar pista");
		use_airstrip(msg.getData());

		char mensaje[msg.size()];
		Logger::getInstance().logMessage(Logger::TRACE, "Leo info de estado pista");
		readedBytes = fifo.read_(static_cast<void*> (&mensaje), sizeof(mensaje));
		if (readedBytes < msg.size()){
			Logger::getInstance().logMessage(Logger::ERROR, "Error al recibir mensaje");

		}
		Message recibido(mensaje,msg.size());
		Logger::getInstance().logMessage(Logger::TRACE, "Info leida, voy a liberar");
		key_t sem_key = recibido.getData();
		Semaforo sem_free_airstrip(sem_key);
		Logger::getInstance().logMessage(Logger::DEBUG, "liberando pista");
		sem_free_airstrip.v();
		Logger::getInstance().logMessage(Logger::TRACE, "Pista liberada, cierro pipe");
		fifo.close_();
	}
}

int main(int argc, char* argv[])
{
	const unsigned int takeoff_request = 1;
	const unsigned int land_request = 2;
	const std::string fifo_name = "./tmp/fifo_requests";
	SharedCounter *counter = NULL;
	//tomar parametros de entrada
	long airplaneID;
	char buffer[255];

	// Parse the ID of the process
	std::stringstream ss;
	ss << argv[1];
	ss >> airplaneID;

	Logger::init();
	sprintf(buffer, "Airplane N°%ld", airplaneID);
	Logger::getInstance().setProcessInformation(buffer);

	WriteFifo fifo(fifo_name);

	try {
		counter = new SharedCounter(SharedCounter::default_path, 'a');
	} catch (std::string & error) {
		Logger::getInstance().logMessage(Logger::ERROR, error);
		return -1;
	}
	try {
		Semaforo msg_enviados(Semaforo::generarClave("/dev/null",'z'));
		Logger::getInstance().logMessage(Logger::TRACE, "Abriendo fifo escritura");
		fifo.open_();
		Logger::getInstance().logMessage(Logger::TRACE, "Fifo abierto");

		Logger::getInstance().logMessage(Logger::TRACE, "Creando fifo lectura");
		std::stringstream name;
		name << "./tmp/Controler_flight";
		name << airplaneID;
		Fifo f_plane_controller(name.str());
		f_plane_controller.create_();
		Logger::getInstance().logMessage(Logger::TRACE, "Fifo lectura creado");

		//simulacion
		Logger::getInstance().logMessage(Logger::DEBUG, "inicia simulación");
		Logger::getInstance().logMessage(Logger::TRACE, "Escribiendo mensaje de despegue");
		Message msg(takeoff_request, airplaneID );
		char * mssg = msg.serialize();
		int wr = fifo.write_(static_cast<void*> (mssg), msg.size());
		delete[] mssg;
		if(wr < msg.size()){
			Logger::getInstance().logMessage(Logger::ERROR, "Error de escritura");
			delete counter;
			return -1;
		} else {
			counter->increment();
			msg_enviados.v();
			Logger::getInstance().logMessage(Logger::DEBUG, "Mensaje enviado");
		}
		get_authorization(TAKEOFF, name.str());

		fly();
		Logger::getInstance().logMessage(Logger::TRACE, "Escribiendo mensaje de aterrizaje");
		Message msg2(land_request, airplaneID);
		char * mssg2 = msg2.serialize();
		wr = fifo.write_(static_cast<void*> (mssg2), msg2.size());
		delete[] mssg2;
		if(wr < msg2.size()){
			Logger::getInstance().logMessage(Logger::ERROR, "Error escritura");
			delete counter;
			return -1;
		} else {
			counter->increment();
			msg_enviados.v();
			Logger::getInstance().logMessage(Logger::DEBUG, "Mensaje enviado");
			delete counter;
			counter = NULL;
		}
		get_authorization(LAND, name.str());
		Logger::getInstance().logMessage(Logger::DEBUG, "finaliza simulación");

		Logger::getInstance().logMessage(Logger::TRACE, "Cierro pipe");
		fifo.close_();
		f_plane_controller.delete_();
	} catch (std::string & error) {
		Logger::getInstance().logMessage(Logger::ERROR, error);
		delete counter;
		return -1;
	}
	return 0;
}
#endif
